package com.xndc.service.iec104.impl;

import com.xndc.netty.iec104.handler.Iec104SessionHandler;
import com.xndc.netty.iec104.model.ASDU;
import com.xndc.netty.iec104.model.IEC104InformationFrame;
import com.xndc.netty.iec104.model.InformationElement;
import com.xndc.netty.iec104.model.InformationObject;
import com.xndc.service.iec104.Iec104CommandService;
import com.xndc.service.iec104.Iec104ConnectionManager;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Calendar;
import java.util.Date;

/**
 * IEC 104命令服务实现
 */
@Slf4j
@Service
public class Iec104CommandServiceImpl implements Iec104CommandService {
    
    @Autowired
    private Iec104ConnectionManager connectionManager;
    
    @Override
    public boolean sendSingleCommand(String deviceId, int ioa, boolean value) {
        log.info("发送单点命令: 设备={}, IOA={}, 值={}", deviceId, ioa, value);
        
        // 获取设备通道
        Channel channel = connectionManager.getChannel(deviceId);
        if (channel == null || !channel.isActive()) {
            log.warn("设备未连接: {}", deviceId);
            return false;
        }
        
        // 创建ASDU
        ASDU asdu = new ASDU();
        asdu.setTypeId((byte)45);  // 单点遥控命令
        asdu.setVsq((byte)1);      // 1个信息对象
        asdu.setCot((byte)6);      // 传送原因: 激活
        
        // 获取公共地址
        int commonAddress = getCommonAddressByDeviceId(deviceId);
        if (commonAddress <= 0) {
            log.warn("未找到设备的公共地址: {}", deviceId);
            return false;
        }
        asdu.setCommonAddress((short)commonAddress);
        
        // 创建信息对象
        InformationObject io = new InformationObject();
        io.setAddress(ioa);
        
        // 创建信息元素
        InformationElement element = new InformationElement();
        element.setSingleCommand(value);
        io.getElements().add(element);
        
        asdu.getInformationObjects().add(io);
        
        // 创建I帧
        IEC104InformationFrame frame = new IEC104InformationFrame();
        
        // 获取序列号
        Iec104SessionHandler sessionHandler = channel.pipeline().get(Iec104SessionHandler.class);
        if (sessionHandler != null) {
            frame.setSendSequence(sessionHandler.getNextSendSequence());
        }
        
        frame.setAsdu(asdu);
        
        // 发送命令
        return connectionManager.sendCommand(deviceId, frame);
    }
    
    @Override
    public boolean sendDoubleCommand(String deviceId, int ioa, byte value) {
        log.info("发送双点命令: 设备={}, IOA={}, 值={}", deviceId, ioa, value);
        
        // 获取设备通道
        Channel channel = connectionManager.getChannel(deviceId);
        if (channel == null || !channel.isActive()) {
            log.warn("设备未连接: {}", deviceId);
            return false;
        }
        
        // 创建ASDU
        ASDU asdu = new ASDU();
        asdu.setTypeId((byte)46);  // 双点遥控命令
        asdu.setVsq((byte)1);      // 1个信息对象
        asdu.setCot((byte)6);      // 传送原因: 激活
        
        // 获取公共地址
        int commonAddress = getCommonAddressByDeviceId(deviceId);
        if (commonAddress <= 0) {
            log.warn("未找到设备的公共地址: {}", deviceId);
            return false;
        }
        asdu.setCommonAddress((short)commonAddress);
        
        // 创建信息对象
        InformationObject io = new InformationObject();
        io.setAddress(ioa);
        
        // 创建信息元素
        InformationElement element = new InformationElement();
        element.setValue(value);
        io.getElements().add(element);
        
        asdu.getInformationObjects().add(io);
        
        // 创建I帧
        IEC104InformationFrame frame = new IEC104InformationFrame();
        
        // 获取序列号
        Iec104SessionHandler sessionHandler = channel.pipeline().get(Iec104SessionHandler.class);
        if (sessionHandler != null) {
            frame.setSendSequence(sessionHandler.getNextSendSequence());
        }
        
        frame.setAsdu(asdu);
        
        // 发送命令
        return connectionManager.sendCommand(deviceId, frame);
    }
    
    @Override
    public boolean sendSetpointCommand(String deviceId, int ioa, float value) {
        log.info("发送设点命令: 设备={}, IOA={}, 值={}", deviceId, ioa, value);
        
        // 获取设备通道
        Channel channel = connectionManager.getChannel(deviceId);
        if (channel == null || !channel.isActive()) {
            log.warn("设备未连接: {}", deviceId);
            return false;
        }
        
        // 创建ASDU
        ASDU asdu = new ASDU();
        asdu.setTypeId((byte)50);  // 设定值命令，浮点数
        asdu.setVsq((byte)1);      // 1个信息对象
        asdu.setCot((byte)6);      // 传送原因: 激活
        
        // 获取公共地址
        int commonAddress = getCommonAddressByDeviceId(deviceId);
        if (commonAddress <= 0) {
            log.warn("未找到设备的公共地址: {}", deviceId);
            return false;
        }
        asdu.setCommonAddress((short)commonAddress);
        
        // 创建信息对象
        InformationObject io = new InformationObject();
        io.setAddress(ioa);
        
        // 创建信息元素
        InformationElement element = new InformationElement();
        element.setValue(value);
        io.getElements().add(element);
        
        asdu.getInformationObjects().add(io);
        
        // 创建I帧
        IEC104InformationFrame frame = new IEC104InformationFrame();
        
        // 获取序列号
        Iec104SessionHandler sessionHandler = channel.pipeline().get(Iec104SessionHandler.class);
        if (sessionHandler != null) {
            frame.setSendSequence(sessionHandler.getNextSendSequence());
        }
        
        frame.setAsdu(asdu);
        
        // 发送命令
        return connectionManager.sendCommand(deviceId, frame);
    }
    
    @Override
    public boolean sendInterrogationCommand(String deviceId) {
        log.info("发送总召唤命令: 设备={}", deviceId);
        
        // 获取设备通道
        Channel channel = connectionManager.getChannel(deviceId);
        if (channel == null || !channel.isActive()) {
            log.warn("设备未连接: {}", deviceId);
            return false;
        }
        
        // 创建ASDU
        ASDU asdu = new ASDU();
        asdu.setTypeId((byte)100);  // 总召唤命令
        asdu.setVsq((byte)1);       // 1个信息对象
        asdu.setCot((byte)6);       // 传送原因: 激活
        
        // 获取公共地址
        int commonAddress = getCommonAddressByDeviceId(deviceId);
        if (commonAddress <= 0) {
            log.warn("未找到设备的公共地址: {}", deviceId);
            return false;
        }
        asdu.setCommonAddress((short)commonAddress);
        
        // 创建信息对象
        InformationObject io = new InformationObject();
        io.setAddress(0);  // 总召唤通常使用IOA=0
        
        // 创建信息元素(总召唤限定词)
        InformationElement element = new InformationElement();
        element.setValue((byte)20);  // 20=站总召唤
        io.getElements().add(element);
        
        asdu.getInformationObjects().add(io);
        
        // 创建I帧
        IEC104InformationFrame frame = new IEC104InformationFrame();
        
        // 获取序列号
        Iec104SessionHandler sessionHandler = channel.pipeline().get(Iec104SessionHandler.class);
        if (sessionHandler != null) {
            frame.setSendSequence(sessionHandler.getNextSendSequence());
        }
        
        frame.setAsdu(asdu);
        
        // 发送命令
        return connectionManager.sendCommand(deviceId, frame);
    }
    
    @Override
    public boolean sendClockSyncCommand(String deviceId) {
        log.info("发送时钟同步命令: 设备={}", deviceId);
        
        // 获取设备通道
        Channel channel = connectionManager.getChannel(deviceId);
        if (channel == null || !channel.isActive()) {
            log.warn("设备未连接: {}", deviceId);
            return false;
        }
        
        // 创建ASDU
        ASDU asdu = new ASDU();
        asdu.setTypeId((byte)103);  // 时钟同步命令
        asdu.setVsq((byte)1);       // 1个信息对象
        asdu.setCot((byte)6);       // 传送原因: 激活
        
        // 获取公共地址
        int commonAddress = getCommonAddressByDeviceId(deviceId);
        if (commonAddress <= 0) {
            log.warn("未找到设备的公共地址: {}", deviceId);
            return false;
        }
        asdu.setCommonAddress((short)commonAddress);
        
        // 创建信息对象
        InformationObject io = new InformationObject();
        io.setAddress(0);  // 时钟同步通常使用IOA=0
        
        // 创建信息元素(时间)
        InformationElement element = new InformationElement();
        element.setTimestamp(getCurrentTimeBytes());
        io.getElements().add(element);
        
        asdu.getInformationObjects().add(io);
        
        // 创建I帧
        IEC104InformationFrame frame = new IEC104InformationFrame();
        
        // 获取序列号
        Iec104SessionHandler sessionHandler = channel.pipeline().get(Iec104SessionHandler.class);
        if (sessionHandler != null) {
            frame.setSendSequence(sessionHandler.getNextSendSequence());
        }
        
        frame.setAsdu(asdu);
        
        // 发送命令
        return connectionManager.sendCommand(deviceId, frame);
    }
    
    /**
     * 获取设备公共地址
     */
    private int getCommonAddressByDeviceId(String deviceId) {
        // 在实际应用中，可能需要从配置或数据库中查找
        // 这里简单返回一个默认值作为示例
        return 1;
    }
    
    /**
     * 获取当前时间的CP56Time2a格式字节数组
     */
    private byte[] getCurrentTimeBytes() {
        // CP56Time2a格式，7字节时间
        byte[] timeBytes = new byte[7];
        
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        
        int milliseconds = cal.get(Calendar.MILLISECOND);
        int second = cal.get(Calendar.SECOND);
        int minute = cal.get(Calendar.MINUTE);
        int hour = cal.get(Calendar.HOUR_OF_DAY);
        int day = cal.get(Calendar.DAY_OF_MONTH);
        int month = cal.get(Calendar.MONTH) + 1; // Calendar月份从0开始
        int year = cal.get(Calendar.YEAR) % 100; // 只取后两位
        
        // 毫秒，占用2字节
        timeBytes[0] = (byte)(milliseconds & 0xFF);
        timeBytes[1] = (byte)((milliseconds >> 8) & 0x01 | (second << 2));
        
        // 分钟，占用1字节，低6位
        timeBytes[2] = (byte)(minute & 0x3F);
        
        // 小时，占用1字节，低5位
        timeBytes[3] = (byte)(hour & 0x1F);
        
        // 日，占用1字节，低5位 | 星期，占用高3位(这里忽略星期)
        timeBytes[4] = (byte)(day & 0x1F);
        
        // 月，占用1字节，低4位
        timeBytes[5] = (byte)(month & 0x0F);
        
        // 年，占用1字节，低7位
        timeBytes[6] = (byte)(year & 0x7F);
        
        return timeBytes;
    }
} 